home *** CD-ROM | disk | FTP | other *** search
/ Mac100% 1998 November / MAC100-1998-11.ISO.7z / MAC100-1998-11.ISO / オンラインソフト定点観測 / ユーティリティ / Mops 3.2.sea / Mops 3.2 / Mops source / PPC source / cg1 < prev    next >
Text File  |  1998-06-22  |  21KB  |  732 lines

  1. marker m__cg1
  2.  
  3.  
  4. ¥                =========================================
  5. ¥                        POWERPC CODE GENERATOR
  6. ¥                =========================================
  7.  
  8. true    constant    assertions?    
  9.             ¥ make it false when everything really works
  10.  
  11. PPC?
  12. [IF]
  13. false    constant    debug?
  14. [ELSE]
  15. false    constant    debug?
  16. [THEN]
  17.  
  18. false    constant    64bit?
  19.  
  20.  
  21. ¥        =============== OPTIMIZATION FLAGS ===============
  22.  
  23. (*    it's useful to be able to turn these off, to find those
  24.     recalcitrant bugs - and in the case of range checking,
  25.     to be able to turn it off for speed-critical tested
  26.     code.  Or for floating multiply-add, someone might want to
  27.     turn it off to restore strict IEEE FP semantics.
  28.     
  29.     NOTE: the default for all these boolean values is TRUE.
  30.  
  31. *)
  32.  
  33. true    value        hoist?                    ¥ can we move ops out of loops if
  34.                                             ¥  they're invariant in the loop?
  35.  
  36. true    value        hoist_fetches?            ¥ can we move fetches to as early
  37.                                             ¥  as possible?
  38.  
  39. true    value        allow_match?            ¥ true if we can eliminate an op if
  40.                                             ¥  we find the result already in
  41.                                             ¥  a register.  Basically the same
  42.                                             ¥  as CSE (common subexpression 
  43.                                             ¥  elimination).
  44.  
  45. true    value        move_by_recompiling?    ¥ can we try to recompile an earlier
  46.                                             ¥  op to avoid a reg move?
  47.  
  48. true    value        optimize_leaf_calls?    ¥ do we use the fast calling sequence
  49.                                             ¥  for leaf definitions?
  50.  
  51. true    value        optimize_branches?        ¥ do we simplify branches over other
  52.                                             ¥  branches, branches to the next
  53.                                             ¥  instruction, etc.?
  54.  
  55. true    value        cascade?                ¥ do we combine ops into single
  56.                                             ¥  instructions where we can?
  57.  
  58. true    value        range_check?            ¥ do we range-check array accesses?
  59.  
  60. true    value        multiply-add?            ¥ do we cascade a floating multiply
  61.                                             ¥  followed by an add into a 
  62.                                             ¥  floating multiply-add instruction
  63.                                             ¥  (or one of its variants)?
  64.  
  65.  
  66. ¥        =============== FORWARD DEFNS ================
  67.  
  68. forward .G
  69. forward .F
  70. forward .C
  71. forward .GS
  72. forward .CS
  73. forward .AL
  74. forward .FAL
  75. forward .FR
  76. forward ZS
  77.  
  78.  
  79.  
  80. ¥            =============== OTHER GLOBALS ==============
  81.  
  82. 0    value    backstop_CDP
  83. 0    value    fetch_backstop
  84. 0    value    basic_block_start
  85. 0    value    loop_start
  86.  
  87. 0    value    max_called_#PL
  88. 0    value    max_called_#FPL
  89.  
  90. false    value        equalizing?        ¥ we don't actually use this one currently
  91. false    value        eq_block_recompiling_move?
  92.  
  93. bytestring            eq_ranges
  94. bytestring            const_data
  95. bytestring            sv_const_data
  96.  
  97.  
  98. (*
  99.  
  100. Notes on PPC code generation:
  101.  
  102. The general way to generate optimized code for an architecture with n
  103. registers is to analyse each basic block and generate a directed acyclic
  104. graph (DAG) whose nodes represent each value generated and whose edges
  105. represent uses of those values.  Note it isn't a tree, since more than
  106. one edge can go into a node.  Then optimization can be done, and common
  107. subexpressions (i.e. nodes) combined.
  108.  
  109. Then, using graph coloring or whatever, the nodes are assigned to
  110. registers.  This assumes there are less regs than nodes, so that we
  111. have to find all dependencies, and re-use a reg when its old value
  112. isn't needed any more.
  113.  
  114. Here we can simplify things a little, and manage everything in one pass.
  115. On the PPC we have so many regs that for normal shortish basic blocks,
  116. we will generally be able to simply assign a different reg for each node.
  117. On the few occasions when we don't have a free reg, we can select one
  118. which has a value with no outstanding references - there's a slight chance
  119. we could have used this value in a subsequent op, but this is pretty well
  120. negligible.  We can optimize on the fly: each time we get a new value,
  121. we can search the reg set for a match so we can use a combined node.
  122.  
  123. This code is invoked as follows:
  124. Whenever Handlers is called to generate 68K code, if PPC? is true,
  125. the Handlers selector and opcode is pushed and PPCvec is executed.
  126. We will set PPCvec to point to PPC_compile which will use the selector
  127. to dispatch to the right routine.
  128.  
  129.  
  130. Notes on memory architecture:
  131.  
  132. On the PPC, code and data is normally kept separate, with the code
  133. being read-only.  The PEF format defines separate code and data sections,
  134. and at launch time these are placed in pointer-based blocks in memory.
  135. We ought to conform to this convention for installed apps, since it will
  136. give the best performance.
  137.  
  138. In the development environment, our dictionary should be in a read-write
  139. block for obvious reasons.  We'll define a separate data area, which
  140. will become the data section of an installed app.  These two areas
  141. can be in handles, which will allow us to resize them on the fly if
  142. necessary.
  143.  
  144. At installation time, we'll generate a PEF in which the dictionary is
  145. added to the existing code section, and the data area is added to the
  146. data section.  Our initial nucleus will probably be generated exactly
  147. this way, either from the 68k or PPC version.  Thus our initial
  148. nucleus is simply an application, which transforms itself into the
  149. Mops development environment by creating a handle for the new dictionary
  150. and data areas.  Now, we could allow the new dictionary area to link
  151. itself to the old one by some cleverness, but since the dic would
  152. only be getting split at one place I don't think it would be worth
  153. the complexity.  Better to just BlockMove the old dic area to the start
  154. of the new when the dev environment is being set up, and likewise for
  155. the data area.
  156.  
  157. Colon uses a new header format incorporating two flag bytes in addition to
  158. what we use on the 68k, and also has to observe 4-byte alignment for the
  159. code.  For this reason we generate a full PPC-style header (including 4-byte
  160. alignment) for colon definitions.  When we compile a call to a colon defn we
  161. have to do PPC-style alignment even on the 68k.  For other types of definition
  162. we don't have to bother, and the code should work on both platforms (since
  163. on the PPC FIND will look after the extra alignment).
  164.    
  165.  
  166. The 2 flag bytes are organized as 4 nybbles:
  167.  
  168. nybble 0:    bit 0:    1 if it's a leaf defn
  169.             bit 1:    1 if it alters the count register
  170.             bit 2:    spare
  171.             bit 3:    1 if it alters any FP reg
  172.  
  173. nybble 1:    number of results in registers on exit
  174. nybble 2:    number of named parameters
  175. nybble 3:    number of named parms + locals
  176.                 (doing it this way is a bit more convenient, and the
  177.                  max number of parms+locals is only 11, so we have
  178.                  enough bits)
  179.  
  180. If the definition does any floating operations or anything that alters
  181. an FP reg, we need more flags, so we add an extra 32 bits.  For
  182. alignment, we have to take at least 32, so we might as well make the
  183. most of it.
  184.  
  185. byte 0:    
  186. byte 1:
  187.  
  188. bytes 2 and 3 are 4 nybbles:
  189.  
  190. nybble 0:
  191. nybble 1:    number of floating results in registers on exit
  192. nybble 2:    number of named floating parameters
  193. nybble 3:    number of named floating parms + locals
  194.  
  195.  
  196.  
  197.  
  198.  
  199.         =============    REGISTER DEFINITIONS:    ================
  200.  
  201. Notes on reg assignment:
  202.  
  203. We need 3 regs for scratch in boilerplate code sequences.  We'll use
  204. r0, which is a bit unusual anyway, and r11 and r12 (see below).
  205.  
  206. r1 is the stack pointer, r2 is RTOC.  We can't monkey with these.
  207. r11 and r12 are used in the calling sequence for external calls.  Apple
  208. says they can be used as scratch at all other times, so we'll use them
  209. in boilerplate sequences.  PowerMacForth does this too, and in the assembler
  210. they're aliased as rX and rY.
  211.  
  212. For external calls, r3-r10 are used for parameters, and r3 for a returned
  213. result.  They won't be saved over the calls.  Of course for internal Mops
  214. calls we can do what we like.  We can use these regs for general operands,
  215. and on an external call normalize the stack so that the required number of
  216. cells are stored in r3 on.  At that stage we won't have any other cached
  217. stack cells, so we don't need the regs preserved anyway.
  218.  
  219. This scenario gives us 8 regs for general operands, i.e. cached stack
  220. cells (r3-r10), which should be enough.  If it turns out not to be enough
  221. we could grab a couple of the regs we've allocated for locals (see below).
  222.  
  223. r13-31 are "non-volatile" - they're saved over external calls.  For
  224. internal Mops calls we just need to save the locals, since other regs
  225. like the base address regs don't get changed.
  226.  
  227. Now for the special regs we need.  These all need to be saved over external
  228. calls, and so are in the non-volatile block.
  229.  
  230. For addressing the dictionary, a difference to the 68k version is that
  231. we need to keep code and data separate (see above).  In the development
  232. environment these will be in handle-based blocks, and in an installed
  233. app they'll be defined in the PEF which will make them end up in pointer-
  234. based blocks.  Anyway, as long as we handle the addressability questions
  235. properly, it shouldn't matter where they are.
  236.  
  237. Code references will be for branches, constants and other constant data
  238. like literal strings and class info.
  239.  
  240. Constants can always be handled via literal instructions.  Even if it
  241. needs more than 16 bits it can be generated in a reg with 2 instructions
  242. which will be faster than a memory reference.
  243.  
  244. Branches will always be self-relative, and they have enough displacement
  245. bits to get us anywhere. 
  246.  
  247. For other constant data, however, it's extremely handy to have a base
  248. reg available, even if these references aren't performance-critical.
  249.  
  250. Thus, if we still have modules (which is still up for grabs), we'll
  251. need 4 base regs - 2 to address code and 2 for data.  Note that on
  252. entry, r2 (RTOC) always points to the start of the data area as defined
  253. in the PEF.  But we can't use RTOC as a regular base reg, since in the
  254. dev environment our data area will be off in a separate handle.
  255.  
  256. Other regs we need are RP (return stack pointer), the loop variable I,
  257. and the base address of the current object.  Now we may as well use one of
  258. our "local" registers for I, since it will be very rare for us to need
  259. all of them.  This will mean one less local in definitions that use I,
  260. but that's not a problem.
  261.  
  262. It seems we should go for a separate FP stack, since the Scientific
  263. Library is now using this.  This will also give better code on the PPC, since
  264. when we bring stack cells back from mem to regs, we'll always know which regs
  265. to move them to.  The floating stack pointer probably should be in a
  266. register.
  267.  
  268. So in all we'll need 7 special regs out of the non-volatile block.
  269.  
  270. This leaves r19-r31 for locals, which means that if we limit the number
  271. of locals to 13, we can keep them all in registers.  This looks reasonable.
  272.  
  273.  
  274. **** Side note: we won't use the lmw and stmw instructions, since Keith D has
  275. warned me that they'll go away in future!  This means that we can use 
  276. their values as pseudo-opcodes, since we know that Mops will never generate
  277. them with their proper meaning.  The values in question are primary opcodes
  278. 46 and 47, which means $B8xxxxxx to $BFxxxxxx.  In particular, we'll
  279. use $BE00 as a handler field for PPC colon definitions.  (Handler fields will
  280. be 4-byte aligned, and so will appear in the same place as instruction
  281. opcodes.)  This will make life easier for the disassembler.
  282.  
  283. Some notes on register handling across internal Mops calls:
  284. Saving and restoring local regs can be a bit long-winded, so to save
  285. space we should normally do what we do on the 68k - that is, at the
  286. start of each defn, save whatever regs we need for locals, and restore
  287. them at the end.  For EXIT, instead of doing everything inline as we
  288. did on the 68k, we'll do a branch to the semicolon.  This is almost as
  289. fast (esp. as it's an unconditional branch), and saves space.
  290.  
  291. We'll probably make an exception for leaf procs, since these get executed
  292. so frequently.  What I'm currently planning, in the case where the leaf
  293. proc has named parms/locals, is to do the houskeeping in the calling
  294. routine instead of in the called leaf proc.  This will give me the
  295. possibility of generating the parms straight in the required regs.
  296. Also I might be able to do the saving and restoring of the needed regs
  297. at the beginning and end of the calling routine (depending on what
  298. parms/locals that routine might need.  This would get these housekeeping
  299. operations out of any inner loops.
  300.  
  301. This alternative calling convention should certainly be faster, but will
  302. take a lot more space, so I won't do it all the time.
  303.  
  304.             ========================================
  305. *)
  306.  
  307.  
  308. 0        constant    CR0
  309.  
  310. 4096    constant    sys_SP_framesize
  311.  
  312. 8        constant    FPcell
  313.  
  314. (* We don't move the stack pointers every time we push and pop something
  315.    - rather, we keep track of the accumulated offset here and only adjust
  316.    when we have to.
  317. *)
  318.  
  319. 0    value    STK_OFFSET    
  320. 0    value    FSTK_OFFSET
  321.  
  322.  
  323. ¥        =================    OD FIELD VALUES    ==================
  324.  
  325. ¥ Here we define various values for OD fields.  We generally use the same
  326. ¥ names as for the 68k code generator, although the values aren't all
  327. ¥ the same (which doesn't matter anyway).
  328.  
  329. ¥ Mode values:
  330.  
  331.  
  332. enum {  mdGPR mdBD mdAbs mdLit mdPC mdFPn  }
  333.  
  334. PPC? [IF] hexx [ELSE] hex [THEN]
  335.  
  336. ¥ Flag byte bits (opFlags field):
  337.  
  338. 0    constant    flExt        ¥ Sign extend
  339. 1    constant    fbExt
  340.  
  341. 1    constant    flFP        ¥ Floating operation
  342. 2    constant    fbFP
  343.  
  344. 2    constant    flLit        ¥ Floating Literal
  345. 4    constant    fbLit
  346.  
  347. 3    constant    flFCR        ¥ FPU constant ROM reference
  348. 8    constant    fbFCR
  349.  
  350. ¥  10    constant    fbNoRecompile?
  351.  
  352.  
  353. ¥ Operation type byte:
  354.  
  355. ¥ 0 means empty, 1 to 7 mean not empty but unknown for some reason.
  356. ¥  So far we've only defined 1 and 2.
  357.  
  358. 1    constant    otUnknown        ¥ isn't empty, but we don't know anything about
  359.                                 ¥  the contents
  360. 2    constant    otUnkStored        ¥ ditto, but we've stored it and so might be
  361.                                 ¥  able to optimize a fetch from the same
  362.                                 ¥  location, even tho we don't know its type
  363. 3    constant    otUnkPulled        ¥ ditto, pulled from memory part of stack
  364.  
  365. 7    constant    otUnknownCodes    ¥ all codes less than or equal to this are
  366.                                 ¥  some kind of empty/unknown
  367.             
  368. 8    constant    otMove            ¥ reg move
  369.  
  370. ¥ the following are also on the 68k, and in target compilation they
  371. ¥  dispatch to us from the 68k interpreter using these codes, so we 
  372. ¥  can't change them.
  373.  
  374. 12    constant    otMUL
  375. 13    constant    otDIV
  376. 14    constant    otUDIV
  377.  
  378. ¥ the following are PPC only:
  379.  
  380. 10    constant    otMULH            ¥ multiply high
  381. 11    constant    otUMULH            ¥ multiply high
  382. 16    constant    otAddc
  383. ¥ 17    constant    otAddic
  384. 17    constant    otAdde
  385. 18    constant    otAddze
  386. 19    constant    otAddme
  387.  
  388. 1A    constant    otSubfc
  389. ¥ 1C    constant    otSubfic
  390. 1B    constant    otSubfe
  391. 1C    constant    otSubfze
  392. 1D    constant    otSubfme
  393.  
  394. ¥ these following are also 68k codes, and can't change
  395.  
  396. 21    constant    otADD
  397. 22    constant    otSUB
  398. 23    constant    otAND
  399. 24    constant    otOR
  400. 25    constant    otXOR
  401. 26    constant    otCMP
  402. 27    constant    otUCMP            ¥ unsigned compare - PPC only
  403.  
  404. 28    constant    otNEG
  405. 29    constant    otNOT
  406.  
  407. 2A    constant    otShift
  408. 2B    constant    otShift&mask    ¥ PPC only
  409. 2C    constant    otTrap            ¥ ditto
  410.  
  411. 30    constant    otPMend            ¥ End of integer ops
  412.  
  413. ¥ 3F    constant    otFPcmp        ¥ Floating-point comparison.  A special case.
  414. 40    constant    otFPstart        ¥ Start of regular floating-point ops.  Note 
  415.                                 ¥  these are NOT in the same order as the 
  416.                                 ¥  integer ops.
  417. 40    constant    otFMOVE
  418. 41    constant    otFADD
  419. 42    constant    otFMUL
  420. 43    constant    otFMADD            ¥ multiply-add - PPC only
  421.  
  422. 48    constant    otFPnoncom        ¥ The following FP ops are non-commutative
  423.  
  424. 48    constant    otFSUB
  425. 49    constant    otFDIV
  426.  
  427. 4F    constant    otFPcmp            ¥ FP comparisons
  428.  
  429. 50    constant    otFPstore
  430. 52    constant    otFPfetch
  431.  
  432.  
  433. 54    constant    otFPmon            ¥ The following FP ops are monadic
  434.  
  435. (*        we don't bother including these in the dictionary, but these
  436.         are the values:
  437.  
  438. 54    constant    otFABS
  439. 55    constant    otFNEG
  440. 56    constant    otFSIN
  441. 57    constant    otFCOS
  442. 58    constant    otFTAN
  443. 59    constant    otFATAN
  444. 5A    constant    otFSQRT
  445. *)
  446.  
  447. 5F    constant    otFPend            ¥ End of FP ops
  448.  
  449. 60    constant    otStore            ¥ Store
  450. 80    constant    otDeferredStore
  451. 62    constant    otFetch            ¥ Direct fetch
  452.  
  453. otFetch
  454.     constant    otAt            ¥ Indirect fetch - ends up being treated
  455.                                 ¥    the same
  456.  
  457. 62    constant    otDUP            ¥ Stack shuffling
  458. 63    constant    ot2DUP
  459. 64    constant    otDROP
  460. 65    constant    ot2DROP
  461. 66    constant    otSWAP
  462. 67    constant    otOVER
  463.  
  464. (*
  465. 68    constant    otNIP
  466. 69    constant    otTUCK
  467. 6A    constant    otROT
  468. 6B    constant    otDOWN
  469. 6C    constant    ot2SWAP
  470. *)
  471.             ¥ For FP stack shuffling, we'll use the corresponding
  472.             ¥  opcodes in the range 72 - 7B, but not bother defining
  473.             ¥  constants and cluttering the dic too much.
  474.  
  475.  
  476. ¥ Subtype byte values:
  477.  
  478. ¥ For comparisons, the top 4 bits of the byte give the condition register field
  479. ¥ bit which we need to branch on for this condition:  LT = 0, GT = 1, EQ = 2.
  480. ¥ The low bit (bit 7) is 1 if the condition we want has a field bit value of 1.
  481. ¥ Bit 6 is 1 for unsigned, and bit 5 is 1 for comparisons with zero.
  482.  
  483. 20    constant    cmpNE
  484. 21    constant    cmpEQ
  485. 00    constant    cmpGE
  486. 01    constant    cmpLT
  487. 10    constant    cmpLE
  488. 11    constant    cmpGT
  489. 02    constant    cmpHS
  490. 03    constant    cmpLO
  491. 12    constant    cmpLS
  492. 13    constant    cmpHI
  493.  
  494. 24    constant    cmpZNE
  495. 25    constant    cmpZEQ
  496. 04    constant    cmpZGE
  497. 05    constant    cmpZLT
  498. 14    constant    cmpZLE
  499. 15    constant    cmpZGT
  500.  
  501. ¥ here's a table to map our 68k comparison codes to the above PPC ones:
  502.  
  503. PPC? [IF]
  504.  
  505.   createx    comparison_codes
  506.     0        cx,        ¥ 0
  507.     0        cx,        ¥ 1
  508.     cmpHI    cx,        ¥ 2
  509.     cmpLS    cx,        ¥ 3
  510.     cmpHS    cx,        ¥ 4
  511.     cmpLO    cx,        ¥ 5
  512.     cmpNE    cx,        ¥ 6
  513.     cmpEQ    cx,        ¥ 7
  514.     0        cx,        ¥ 8
  515.     0        cx,        ¥ 9
  516.     0        cx,        ¥ A
  517.     0        cx,        ¥ B
  518.     cmpGE    cx,        ¥ C
  519.     cmpLT    cx,        ¥ D
  520.     cmpGT    cx,        ¥ E
  521.     cmpLE    cx,        ¥ F
  522.  
  523. decimalx
  524.  
  525. [ELSE]
  526.  
  527.   create comparison_codes
  528.  
  529.     0        c,        ¥ 0
  530.     0        c,        ¥ 1
  531.     cmpHI    c,        ¥ 2
  532.     cmpLS    c,        ¥ 3
  533.     cmpHS    c,        ¥ 4
  534.     cmpLO    c,        ¥ 5
  535.     cmpNE    c,        ¥ 6
  536.     cmpEQ    c,        ¥ 7
  537.     0        c,        ¥ 8
  538.     0        c,        ¥ 9
  539.     0        c,        ¥ A
  540.     0        c,        ¥ B
  541.     cmpGE    c,        ¥ C
  542.     cmpLT    c,        ¥ D
  543.     cmpGT    c,        ¥ E
  544.     cmpLE    c,        ¥ F
  545.  
  546. decimal
  547.  
  548. [THEN]
  549.  
  550. 0    value        OPERATION
  551. 0    value        SUBOPERATION
  552.  
  553. ¥ Some types of instruction need special treatment - e.g. AND etc. use the
  554. ¥ rA field for the destination.  So we define some types:
  555.  
  556. enum {    noType  loadStoreType  arithType  logicalType  cmpType  branchType  shiftType  }
  557.  
  558.  
  559.  
  560. ¥        =================    UTILITY WORDS    ==================
  561.  
  562. : MONADIC?    ¥ ( opcode -- opcode b )
  563.     otNeg  otNot    within?  IF  true  EXIT  THEN
  564.     otFPmon otFPend    within?
  565. ;
  566.  
  567. : MEM_REFERENCING?    ¥ ( opcode -- b )
  568.  
  569.     SELECT[    otFetch        ],
  570.           [ otStore        ],
  571.           [ otFPFetch    ],
  572.           [    otFPStore    ]=>        true
  573.                   DEFAULT=>        drop false
  574.     ]SELECT
  575. ;
  576.     
  577.  
  578. PPC?
  579. [IF]
  580. : dasm  ;            ¥ can't disassemble in native mode yet!
  581. : z  ;
  582.  
  583. [ELSE]
  584.  
  585. forward dasm        ¥ disassembles what we've done so far
  586. forward dcurr        ¥ disassembles the current defn (even if not finished)
  587. forward Z            ¥ ends ppc compilation and disassembles.
  588.  
  589. [THEN]
  590.  
  591.  
  592. ¥ GetImmediateOp does the same when we're going to execute the operation
  593. ¥ now, returning the xt of the word to execute.
  594.  
  595. : GETIMMEDIATEOP  { opType subtype -- xt }
  596.     opType
  597.     SELECT[    otAdd    ]=>        ['] +
  598.           [    otSub    ]=>        ['] -
  599.           [    otAND    ]=>        ['] and
  600.           [    otOR    ]=>        ['] or
  601.           [    otXOR    ]=>        ['] xor
  602.           [    otMUL    ]=>        ['] *
  603.           [    otDIV    ]=>        ['] /
  604.           
  605.           [    otNEG    ]=>        ['] negate
  606.           [    otNOT    ]=>        ['] not
  607.  
  608.           [    otCMP    ]=>
  609.                   subtype
  610.                   CASE[ cmpNE    ]=>        ['] <>
  611.                     [ cmpEQ    ]=>        [']    =
  612.                     [ cmpGE    ]=>        ['] >=
  613.                     [ cmpLT    ]=>        ['] <
  614.                     [ cmpLE    ]=>        ['] <=
  615.                     [ cmpGT    ]=>        ['] >
  616.                     [ cmpZNE ]=>    ['] 0<>
  617.                     [ cmpZEQ ]=>    ['] 0=
  618.                     [ cmpZGE ]=>    ['] 0>=
  619.                     [ cmpZLT ]=>    ['] 0<
  620.                     [ cmpZLE ]=>    ['] 0<=
  621.                     [ cmpZGT ]=>    ['] 0>
  622.  
  623.                 DEFAULT=>    cr .h ."  undef otCMP subtype in getImmediateOp" 1 die
  624.                 ]CASE
  625.  
  626.           [    otUCMP    ]=>
  627.                   subtype
  628.                   CASE[ cmpHS    ]=>        ['] u>=
  629.                     [ cmpLO    ]=>        ['] u<
  630.                     [ cmpLS    ]=>        ['] u<=
  631.                     [ cmpHI    ]=>        ['] u>
  632.                 DEFAULT=>    cr .h ."  undef otUCMP subtype in getImmediateOp" 1 die
  633.                 ]CASE
  634.  
  635.           [    otShift    ]=>
  636.                   subtype
  637.                   CASE[ 0    ]=>        ['] <<
  638.                     [ 1    ]=>        ['] >>
  639.                 DEFAULT=>    cr .h ."  undef otShift subtype in getImmediateOp" 1 die
  640.                 ]CASE
  641.  
  642.         DEFAULT=>        cr .h ."  undef op passed to getImmediateOp" 1 die
  643.     ]SELECT
  644. ;
  645.  
  646. PPC? not
  647. [IF]        ¥ we put this in pnuc3 in target mode
  648.  
  649. ¥ 16bits? ( n signed? -- n b )
  650. ¥  returns true if n will fit in 16 bits (signed or unsigned as requested).
  651.  
  652. : 16BITS?    ¥ ( n signed? -- n b )
  653.     IF    -32768 32767  within?
  654.     ELSE
  655.         dup 16 >> 0=
  656.     THEN
  657. ;
  658.  
  659. [THEN]
  660.  
  661. : SIGNED?    ¥ ( operation - b )
  662.             ¥ Returns true if this is a signed op - assumed to be the
  663.             ¥  default.  We just return false for the specific unsigned
  664.             ¥  ops, and true for everything else.
  665.  
  666.     SELECT[    otUDIV    ],
  667.           [    otAND    ],
  668.           [    otOR    ],
  669.           [    otXOR    ],
  670.           [    otUCMP    ]=>        false
  671.         DEFAULT=>            drop  true
  672.     ]SELECT
  673. ;
  674.  
  675.  
  676. : REVERSE_COMPARISON    ¥ called if we swap operands of a compare.  Adjust 
  677.                         ¥  subOperation appropriately.
  678.  
  679.     subOperation $ 24 and  ?EXIT        ¥ out if monadic or EQ or NE
  680.     $ 10  xor> subOperation  ;
  681.  
  682.  
  683. ¥ This must come before we redefine @ABS below!
  684.  
  685. PPC? not
  686. [IF]
  687. from pasmMod import{    :PPC_code  ;PPC_code
  688.                         disasm  disasm_word  disasm_xt
  689.                         disasm_rng  disasm_cnt  disasm_one
  690.                         set_disasm_call_range  }
  691.  
  692. compile: pasmMod
  693.  
  694.  
  695. ¥ While still in 68k-land, we need a PPC-style reloc! and @abs.  The proper
  696. ¥  PPC versions will be compiled in pnuc3 and setup respectively.  Note,
  697. ¥  any changes must of course be made in both places.
  698.  
  699. : RELOC!  { theAddr dest -- }
  700.     theAddr addr>S&D
  701.     $ ffffff and  swap  24 <<  or
  702.     dest !
  703. ;
  704.  
  705.  
  706. : reloc,        DP    reloc!  4 ++> DP   ;
  707. : relocCode,    CDP reloc!  4 ++> CDP  ;
  708. : displCode,    CDP displ!    4 ++> CDP  ;
  709.  
  710.  
  711. ¥ In the target compilation, we only have 4 segments.
  712.  
  713. : @ABS  { addr ¥ relocAddr seg# displ -- absAddr }
  714.     addr @  -> relocAddr
  715.     relocAddr  $ ffffff and  -> displ
  716.     relocAddr  24 >>  -> seg#
  717.     seg#
  718.     SELECT[    8    ]=>        code_start
  719.           [    9    ]=>        data_start
  720.           [    10    ]=>        seg_code_start
  721.           [    11    ]=>        seg_data_start
  722.     DEFAULT=>    ." not a reloc addr" 1 die
  723.     ]SELECT
  724.     displ +
  725. ;
  726.  
  727.  
  728. : @abs6        @abs  ;            ¥ a variant name we can call later when @abs
  729.                             ¥  has been redefined in the PPC image
  730.  
  731. [THEN]
  732.